import { routerRedux } from 'dva/router';
import { message, Modal } from 'antd';
import { setLocale } from 'umi/locale';
import { stringify } from 'qs';
import isObject from 'lodash/isObject';
import moment from 'moment';
import mapping, {
  login,
  logout,
  getVcodeFlag,
  changeRole,
  unlock,
  ssoLogin,
  logged,
  status,
} from '@/services/login';
import traceLogAction from '@/services/traceLogAction';
import {
  getPageQuery,
  setItem,
  getItem,
  storageClear,
  getViewMode,
  parseQuery,
} from '@/utils/utils';
import { reloadAuthorized } from '@/utils/Authorized';
import { setAuthority } from '@/utils/authority';
import { enableWatermark, loginRedirect, visitor } from '@/defaultSettings';
import config from '../../config/config';
import watermark from '@/utils/waterMark';
import userInfo from '@/userInfo';

const initState = {
  status: mapping.LOG_OUT,
  user: null,
  mode: 'password', // password:密码方式登录; sms: 短信验证码方式登录; qr: 扫二维码登陆
  needVerifyCode: false, // 决定是否追加输入验证码
  isRemenber: false, // 是否记住密码
  forceLogin: false, // 23点之后需要强制才可以登录
  needModifyPsw: false, // 初始化密码需要修改后才能登陆
  verifyCode: null,
};

const isOk = response => {
  return new Promise((resolve, reject) => {
    Modal.confirm({
      title: `现在为非工作时间，确定要登录系统吗?`,
      content: `工作时间为：${response.resultMsg}`,
      onOk() {
        resolve(true);
      },
      onCancel() {
        // eslint-disable-next-line prefer-promise-reject-errors
        reject(false);
      },
    });
  });
};

const needModifyPsw = () => {
  return new Promise((resolve, reject) => {
    Modal.confirm({
      title: `初始密码需要修改后才能登录`,
      content: `确定现在修改吗?`,
      onOk() {
        resolve(true);
      },
      onCancel() {
        // eslint-disable-next-line prefer-promise-reject-errors
        reject(false);
      },
    });
  });
};

/**
 * 更新session数据，以及刷新权限
 * @param {object} obj
 */
function handle(obj) {
  /**
   * 提取数组中每一项的sysRoleCode
   * 清空sessionStorage，并记录当前用户信息
   * request中根据这个字段判断session失效并拦截
   *
   */
  const sysRoleCodes = [];
  if (Array.isArray(obj.portalRoles)) {
    obj.portalRoles.forEach(item => {
      if (item.sysRoleCode !== undefined) {
        sysRoleCodes.push(item.sysRoleCode);
      }
    });
  }
  storageClear();
  setItem('user', obj);
  setItem('status', mapping.LOGINED);
  setAuthority(sysRoleCodes);
  // 刷新权限组件
  reloadAuthorized();
}

function getPathname(history) {
  const urlParams = new URL(window.location.href);
  const { pathname, hash } = urlParams;
  let result = '/';
  if (history === 'hash' && hash !== '') {
    result = hash.slice(1);
  }
  if (history === 'brower' && pathname !== '') {
    result = pathname;
  }
  // 如果是登录页，直接进到首页
  if (result.startsWith('/user')) {
    result = '/';
  }
  return result;
}

export default {
  namespace: 'login',

  state: {
    status: visitor === true ? mapping.LOGINED : mapping.CONFIRMING, //  'CONFIRMING','LOG_OUT','LOGINED','SESSION_TIME_OUT', 'LOCKED'
    user: visitor === true ? userInfo : getItem('user'),
  },

  effects: {
    *checkLogin(_, { call, put }) {
      const response = yield call(logged);
      const { resultCode, ...rest } = response;
      /**
       * 1、先通过logged.do接口查询是否已登录，resultCode=='0000'表示已登录（且预期回参与login.do成功登录时一致）
       * 2、若已登录需进一步查询是否是锁屏或超时
       */
      if (`${resultCode}` === mapping.SUCC_CODE) {
        const resp = yield call(status, moment().format('YYYY-MM-DD HH:mm:ss'));
        // 登录超时或被管理员强制下线
        if (resp.sessionTimeout === true) {
          // LoginInfo.timeoutFlag = true;
          if (!resp.invalidateMsg) {
            resp.invalidateMsg = '登录会话超时';
          }
          Modal.warning({
            title: '提醒',
            content: `${resp.invalidateMsg}，请重新登录`,
          });
          yield put({
            type: 'logout',
          });
        } else if (resp.lockFlag === true) {
          yield put({
            type: 'lock',
            payload: { user: rest },
          });
        } else {
          const sw = traceLogAction.newStopwatch();
          /**
           * 登录成功记录登录日志
           */
          traceLogAction.traceLoginInfo({
            operDuration: sw.duration(),
          });

          /**
           * 更新model中的user和status
           * 重置initState中的字段，为了保证下次登陆初始化状态
           */
          yield put({
            type: 'loginSuccess',
            payload: { ...rest, status: mapping.LOGINED, initState },
          });

          // 更新session
          handle(rest);
          yield put({
            type: 'redirect',
          });
        }
      } else {
        yield put({
          type: 'update',
          payload: { status: mapping.LOG_OUT },
        });
      }
    },
    *getInitData({ payload }, { call, put }) {
      const response = yield call(getVcodeFlag, payload);
      yield put({
        type: 'needVerifyCode',
        payload: response,
      });
    },

    *login({ payload }, { call, put }) {
      const sw = traceLogAction.newStopwatch();
      // 预期的回参格式见 mock/login.js
      const response = yield call(login, payload);
      if (response === null) {
        return;
      }
      // Login successfully
      if (`${response.resultCode}` === mapping.SUCC_CODE) {
        const { resultCode, ...rest } = response;
        /**
         * 登录成功记录登录日志
         */
        traceLogAction.traceLoginInfo({
          operDuration: sw.duration(),
        });

        /**
         * 更新model中的user和status
         * 重置initState中的字段，为了保证下次登陆初始化状态
         */
        yield put({
          type: 'loginSuccess',
          payload: { ...rest, status: mapping.LOGINED, initState },
        });

        // 更新session
        handle(rest);
        yield put({
          type: 'redirect',
        });
      } else if (`${response.resultCode}` === mapping.LOGIN_ERROR_NON_WORK_HOUR) {
        // 非工作时间登陆
        yield put({
          type: 'confirm',
          payload: response,
        });
      } else if (`${response.resultCode}` === mapping.LOGIN_ERROR_DEFAULT_PWD) {
        // 初始密码需要修改后才能登录
        yield put({
          type: 'confirm2',
          payload: response,
        });
      } else {
        /**
         * 打开验证码
         */
        yield put({
          type: 'needVerifyCode',
          payload: true,
        });
        yield put({
          type: 'addVerifyCode',
        });
        message.error(response.resultMsg);
      }
    },
    *redirect(_, { put }) {
      /**
       * 如果location包含redirect，登陆成功后跳转到指目标页面
       */
      const urlParams = new URL(window.location.href);
      const { history } = config; // 'browser','hash','memory'
      const params = getPageQuery();
      let { redirect } = params;
      if (redirect) {
        const redirectUrlParams = new URL(redirect);
        if (redirectUrlParams.origin === urlParams.origin) {
          redirect = redirect.substr(urlParams.origin.length);
          if (redirect.match(/^\/.*#/)) {
            redirect = redirect.substr(redirect.indexOf('#') + 1);
          }
        } else {
          window.location.href = redirect;
          return;
        }

        if (loginRedirect === true) {
          yield put(routerRedux.replace(redirect));
        } else {
          yield put(routerRedux.replace('/'));
        }
      } else {
        yield put(routerRedux.replace(getPathname(history)));
      }
    },
    *logout(_, { call, put }) {
      // 记录登出轨迹
      yield call(traceLogAction.traceLog, {
        serviceCode: '413010050002',
        serviceName: '登出系统',
        operStatus: '成功',
      });
      // 通知后台用户登出
      yield call(logout);
      // 重置model中的status和user
      yield put({
        type: 'clear',
      });
      // 防止重复追加redirect
      if (window.location.href.indexOf('user/login?redirect=http') === -1) {
        let obj = {
          pathname: '/user/login',
        };

        // 重定向开关
        if (loginRedirect === true) {
          obj = {
            ...obj,
            search: stringify({
              redirect: window.location.href,
            }),
          };
        }
        yield put(routerRedux.push(obj));
      }
    },

    /**
     * 角色切换
     * 1、更新当前用户信息
     * 2、更新跟角色相关的菜单信息
     * @param {number} payload 角色ID
     */
    *changeRole({ payload }, { call, put }) {
      const response = yield call(changeRole, { roleId: payload });

      if (response === null) {
        return;
      }
      // Login successfully
      if (`${response.resultCode}` === mapping.SUCC_CODE) {
        const { resultCode, ...rest } = response;

        /**
         * 更新model中的user和status
         * 重置initState中的字段，为了保证下次登陆初始化状态
         */
        yield put({
          type: 'loginSuccess',
          payload: { ...rest, status: mapping.LOGINED, initState },
        });

        // 更新跟角色相关的菜单信息
        yield put({
          type: 'menu/getInitData',
        });
        // 更新session
        handle(rest);
      } else if (response.resultMsg) {
        message.error(response.resultMsg);
      }
    },
    *confirm({ payload }, { call, put }) {
      const promise = yield call(isOk, payload);
      if (promise === true) {
        yield put({
          type: 'forceLogin',
        });
      }
    },
    *confirm2({ payload }, { call, put }) {
      const promise = yield call(needModifyPsw, payload);
      if (promise === true) {
        yield put({
          type: 'update',
          payload: {
            needModifyPsw: true,
          },
        });
      }
    },
    *unlock({ payload }, { call, put }) {
      const response = yield call(unlock, payload);
      // 初始密码也认为是解锁成功
      if (
        mapping.SUCC_CODE === response.resultCode ||
        response.resultCode === mapping.LOGIN_ERROR_DEFAULT_PWD
      ) {
        yield put({
          type: 'logined',
        });
      } else {
        message.error(response.resultMsg);
      }
    },
    *ssoLogin({ payload }, { call, put }) {
      const response = yield call(ssoLogin, payload);
      // const { success } = response;
      // const { language } = parseQuery(window.location.href);
      // if (resultCode === '0') {
      //   // 更新session
      //   handle(resultObject);
      //   /**
      //    * - url中包含有效language则提取使用
      //    * - 不包含则默认中文
      //    * TODO: 这块设置国际化应该弱到subscriptions.setup处做监听
      //    */
      //   if (['zh-CN', 'en-US'].indexOf(language) !== -1) {
      //     setLocale(language);
      //   } else {
      //     setLocale('zh-CN');
      //   }
      //   yield put({
      //     type: 'loginSuccess',
      //     payload: { ...resultObject, status: mapping.LOGINED, initState },
      //   });
      // }
    },
    *clear(_, { put }) {
      // 擦掉session storage中的数据
      storageClear();
      reloadAuthorized();
      // 防止登录页出现水印
      if (enableWatermark) {
        watermark.remove();
      }
      yield put({
        type: 'reset',
      });
      yield put({
        type: 'menu/reset',
      });
    },
  },

  reducers: {
    reset() {
      return initState;
    },
    update(state, { payload }) {
      return {
        ...state,
        ...payload,
      };
    },
    updateAvatar(state, { payload }) {
      const { avatar } = payload;
      const { user } = state;
      if (isObject(user.userInfo)) {
        user.userInfo.userPhoto = avatar;
      }
      setItem('user', user);
      return {
        ...state,
        user,
      };
    },
    loginSuccess(state, { payload }) {
      const { status, initState, ...rest } = payload;
      return {
        ...state,
        ...initState,
        status,
        user: rest,
      };
    },
    needVerifyCode(state, { payload }) {
      return {
        ...state,
        needVerifyCode: payload,
      };
    },
    forceLogin(state) {
      return {
        ...state,
        forceLogin: true,
      };
    },
    sessionTimeout(state) {
      storageClear();
      return {
        ...state,
        user: null,
        status: mapping.SESSION_TIME_OUT,
      };
    },
    lock(state, { payload }) {
      setItem('status', mapping.LOCKED);
      if (payload) {
        return {
          ...state,
          status: mapping.LOCKED,
          user: payload.user,
        };
      }
      return {
        ...state,
        status: mapping.LOCKED,
      };
    },
    logined(state) {
      return {
        ...state,
        status: mapping.LOGINED,
      };
    },
    addVerifyCode(state) {
      return {
        ...state,
        verifyCode: `portal/LoginController/vcode.do?${new Date().getTime()}`,
      };
    },
    clearVerifyCode(state) {
      return {
        ...state,
        verifyCode: null,
      };
    },
  },
  subscriptions: {
    setup({ dispatch, history }) {
      return history.listen(() => {
        // 只在viewMode发生改变之后才更新
        // window.g_app._store.getState().setting取到的值表示当前的视图模式
        // TODO: 还需要监听inner模式下language的变化并通过设置setLocale促使页面刷新，改变国际化文本
        if (
          window.g_app._store.getState().setting &&
          window.g_app._store.getState().setting.viewMode !== getViewMode()
        ) {
          dispatch({
            type: 'setting/updateViewMode',
            payload: {
              viewMode: getViewMode(),
            },
          });
        }
      });
    },
  },
};
